#include "VisualizerState.h"
#include "VisCamController.h"
#include "GeometryGenerator.h"

#include "Overseer.h"
#include "GUIManager.h"
#include "InputManager.h"

#include "Settings.h"

#include <Ogre.h>
#include <SkyX.h>

#include <iostream>

VisualizerState::VisualizerState(Overseer *o, GeometryGenerator *gg) : State(o), geometryGenerator(gg)
{
    root = Ogre::Root::getSingletonPtr();
    smgr = geometryGenerator->getSceneManager();
}

void VisualizerState::initialise()
{
    Settings *settings = Settings::getSingletonPtr();
    overseer->getGUIManager()->executeScript("visualizer.lua");

    camera = smgr->getCamera("OverseerCam");
    camera->setNearClipDistance(5);

    geometryGenerator->setCamera(camera);

    vp = root->getAutoCreatedWindow()->addViewport(camera);
    vp->setBackgroundColour(Ogre::ColourValue::Black);
    camera->setAspectRatio(Ogre::Real(vp->getActualWidth()) / Ogre::Real(vp->getActualHeight()));
    camera->setPosition(Ogre::Vector3(0,0,80));
    camera->lookAt(Ogre::Vector3(0,0,-300));
    camController = new VisCamController(camera);
    overseer->getInputManager()->addKeyListener(camController, "Camera Controller");
    overseer->getInputManager()->addMouseListener(camController, "Camera Controller");

    camera->setPosition(geometryGenerator->getInitialCameraPosition());

    skyXController = new SkyX::BasicController;
    skyX = new SkyX::SkyX(smgr, skyXController);
    skyX->create();
    root->addFrameListener(skyX);
    root->getAutoCreatedWindow()->addListener(skyX);
    skyX->getCloudsManager()->add(SkyX::CloudLayer::Options());
    //camera->setPolygonMode(Ogre::PM_WIREFRAME);

    smgr->setAmbientLight(Ogre::ColourValue(0.25,0.25,0.25));

    light = smgr->createLight("MainLight");
    light->setType(Ogre::Light::LT_DIRECTIONAL);
    
    
    Ogre::Vector3 lightDirection = -skyXController->getSunDirection();
    light->setDirection(lightDirection);
    
    Ogre::Real sunValue = 2.0/(1.0+Ogre::Math::Exp(-15*(Ogre::Math::Sin(-lightDirection.y*Ogre::Math::PI/2.0))))-1.0;
    light->setDiffuseColour(Ogre::ColourValue(sunValue,sunValue,0.94*sunValue,1.0));
    light->setSpecularColour(Ogre::ColourValue(1.0,1.0,1.0));
    
    skyXController->setTime(Ogre::Vector3(settings->getSetting<double>("Time.StartingTime"),settings->getSetting<double>("Time.Sunrise"),settings->getSetting<double>("Time.Sunset")));
    skyX->setTimeMultiplier(settings->getSetting<double>("Time.TimeMultiplier"));
    //skyX->getGPUManager()->addGroundPass(static_cast<Ogre::MaterialPtr>(Ogre::MaterialManager::getSingleton().getByName("TriplanarTexturing"))->getTechnique(0)->createPass(), 5000, Ogre::SBT_TRANSPARENT_COLOUR);
}


void VisualizerState::pause()
{
}

void VisualizerState::resume()
{
}

void VisualizerState::update(double timeSinceLastFrame)
{
    camController->update(timeSinceLastFrame);
    geometryGenerator->notifyCameraPosition(camera->getPosition());
    geometryGenerator->update(timeSinceLastFrame);
    Ogre::Vector3 lightDirection = -skyXController->getSunDirection();

    Ogre::Real ambientValue = lightDirection.y < 0 ? -lightDirection.y : 0;
    ambientValue = Ogre::Math::Clamp<Ogre::Real>(Ogre::Math::Pow(ambientValue,0.25),0.1,0.25);
    smgr->setAmbientLight(Ogre::ColourValue(ambientValue,ambientValue,ambientValue,1.0));

    if (lightDirection.y < 0)
    {
        Ogre::Real sunValue = 2.0/(1.0+Ogre::Math::Exp(-15*(Ogre::Math::Sin(-lightDirection.y*Ogre::Math::PI/2.0))))-1.0;
        light->setDiffuseColour(Ogre::ColourValue(sunValue,sunValue,0.94*sunValue,1.0));
    }
    else
    {
        lightDirection = -skyXController->getMoonDirection();
        Ogre::Real moonValue = 2.0/(1.0+Ogre::Math::Exp(-15*(Ogre::Math::Sin(-lightDirection.y*Ogre::Math::PI/2.0))))-1.0;
        light->setDiffuseColour(0.25*moonValue,0.25*moonValue,0.3*moonValue);
    }
    light->setDirection(lightDirection);
}

void VisualizerState::exit()
{
    overseer->getInputManager()->removeKeyListener("Camera Controller");
    overseer->getInputManager()->removeMouseListener("Camera Controller");
    delete camController;
    delete geometryGenerator;
}

bool VisualizerState::keyPressed(const OIS::KeyEvent &evt)
{
    switch (evt.key)
    {
    case OIS::KC_ESCAPE:
        overseer->exit();
        break;
    default:
        break;
    }
    return true;
}
bool VisualizerState::keyReleased(const OIS::KeyEvent &evt)
{
    return true;
}
bool VisualizerState::mouseMoved(const OIS::MouseEvent &evt)
{
    return true;
}
bool VisualizerState::mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID id)
{
    return true;
}
bool VisualizerState::mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID id)
{
    return true;
}
